﻿extern alias pcl;
using System.Diagnostics;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
using Windows.Storage.Streams;
using IDeriveBytes = pcl::System.Security.Cryptography.Adaptation.IDeriveBytes;

namespace System.Security.Cryptography.Adaptation
{
    // Adapts a WinRT KeyDerivationAlgorithmProvider to a IDeriveBytes
    //TODO : Fix this for enable registration
    public class Rfc2898DeriveBytesAdapter : IDeriveBytes
    {
        private readonly CryptographicKey _password;
        private int _iterationCount;
        private byte[] _salt;

        public Rfc2898DeriveBytesAdapter(string algorithmName, string password)
        {
            Debug.Assert(algorithmName != null && algorithmName.Length > 0);

            KeyDerivationAlgorithmProvider provider = KeyDerivationAlgorithmProvider.OpenAlgorithm(algorithmName);
            //changed because the different encoding between WA and UTF8
            //IBuffer buffer = CryptographicBuffer.ConvertStringToBinary(password, BinaryStringEncoding.Utf8);
            byte[] hashed_string = Text.Encoding.GetEncoding("iso-8859-1").GetBytes(password);
            IBuffer buffer = CryptographicBuffer.CreateFromByteArray(hashed_string);
            _password = provider.CreateKey(buffer);
        }
        //try to modify the method to accept the bytearray password
        public Rfc2898DeriveBytesAdapter(string algorithmName, byte[] password)
        {
            Debug.Assert(algorithmName != null && algorithmName.Length > 0);

            KeyDerivationAlgorithmProvider provider = KeyDerivationAlgorithmProvider.OpenAlgorithm(algorithmName);


            IBuffer buffer = CryptographicBuffer.CreateFromByteArray(password);


            // create a key based on original key and derivation parameters

            //changed because the different encoding between WA and UTF8
            //IBuffer buffer = CryptographicBuffer.ConvertStringToBinary(password, BinaryStringEncoding.Utf8);
            //byte[] hashed_string = Text.Encoding.GetEncoding("iso-8859-1").GetBytes(password);
            //IBuffer buffer = CryptographicBuffer.CreateFromByteArray(password);

            _password = provider.CreateKey(buffer);
        }

        public Rfc2898DeriveBytesAdapter(string algorithmName, byte[] password, byte[] salt, int keySizeInBytes)
        {
            Debug.Assert(algorithmName != null && algorithmName.Length > 0);

            KeyDerivationAlgorithmProvider provider = KeyDerivationAlgorithmProvider.OpenAlgorithm(algorithmName);

            IBuffer saltBuffer = CryptographicBuffer.CreateFromByteArray(salt);
            IBuffer buffer = CryptographicBuffer.CreateFromByteArray(password);
            KeyDerivationParameters pbkdf2Parms =
                    KeyDerivationParameters.BuildForPbkdf2(saltBuffer, (uint)128);

            // create a key based on original key and derivation parameters
            CryptographicKey keyOriginal = provider.CreateKey(buffer);
            IBuffer keyMaterial = CryptographicEngine.DeriveKeyMaterial(keyOriginal, pbkdf2Parms, (uint)keySizeInBytes);
            _password = keyOriginal;
            
        }

        public int IterationCount
        {
            get { return _iterationCount; }
            set
            {
                if (value < 0)
                    throw new ArgumentOutOfRangeException("value");

                _iterationCount = value;
            }
        }

        public byte[] Salt
        {
            get { return (byte[])_salt.Clone(); }
            set
            {
                if (value == null)
                    throw new ArgumentNullException("salt");

                if (value.Length < 8)
                    throw new ArgumentException("Salt Length < 8");

                _salt = (byte[])value.Clone();
            }
        }

        public byte[] GetBytes(int cb)
        {
            if (cb < 0)
                throw new ArgumentOutOfRangeException("cb");

            KeyDerivationParameters parameters = KeyDerivationParameters.BuildForPbkdf2(_salt.AsBuffer(), (uint)_iterationCount);

            IBuffer keyMaterial = CryptographicEngine.DeriveKeyMaterial(_password, parameters, (uint)cb);

            return keyMaterial.ToArray();
        }

        public void Reset()
        {
        }

        public void Dispose()
        {
        }
    }
}
